package com.sywl.hibernate;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;

import com.sywl.web.util.SortOrder;

/**
 * JPA缓存查询实现
 * 使用之前需要配置二级缓存
 * @author itachi
 *
 */
public class QueryCacheImpl implements QueryCache {
	
	@PersistenceContext
	transient EntityManager em;
	
	@Override
	public EntityManager getEntityManager() {
		return em;
	}
	
	@Override
	public <T> T find(long id, Class<T> clazz) {
		return em.find(clazz, id);
	}

	@Override
	public <T> List<T> query(int first, int maxResult, Class<T> clazz) {
		return queryBySort(first, maxResult, "id", clazz, SortOrder.ASC);
	}

	@Override
	public <T> List<T> queryBySort(int first, int maxResult, String sortField,
			Class<T> clazz, SortOrder sortOrder) {
		String sql = "from " + clazz.getName() + " order by " + sortField + " " + sortOrder.name();
		return createQuery(sql, first, maxResult, clazz).getResultList();
	}

	@Override
	public Object querySingleResult(String sql) {
		return createQuery(sql, 0, 1, Object.class).getSingleResult();
	}
	
	@Override
	public Object querySingleResult(Query query) {
		return query.setFirstResult(0).setMaxResults(1).setHint("org.hibernate.cacheable", true).getSingleResult();
	}
	
	@Override
	public <T> Object querySingleResult(TypedQuery<T> query) {
		return query.setFirstResult(0).setMaxResults(1).getSingleResult();
	}

	@Override
	public <T> List<T> query(String sql, int first, int maxResult,
			Class<T> clazz) {
		return createQuery(sql, first, maxResult, clazz).getResultList();
	}
	
	@Override
	public <T> List<T> query(TypedQuery<T> query, int first, int maxResult, Class<T> clazz) {
		return createQuery(query, first, maxResult, clazz).getResultList();
	}
	
	@Override
	public <T> long count(Class<T> clazz) {
		return (Long)querySingleResult("select count(o) from " + clazz.getName() + " o");
	}
	
	@Override
	public <T> List<T> findAll(Class<T> clazz) {
		return query(0, (int)count(clazz), clazz);
	}
	
	@Override
	public Query createQuery(String sql) {
		return em.createQuery(sql).setHint("org.hibernate.cacheable", true);
	}
	
	@Override
	public <T> TypedQuery<T> createQuery(String sql, Class<T> clazz) {
		return em.createQuery(sql, clazz).setHint("org.hibernate.cacheable", true);
	}
	
	@Override
	public <T> TypedQuery<T> createQuery(String sql, int first, int maxResult, Class<T> clazz) {
		return createQuery(em.createQuery(sql, clazz), first, maxResult, clazz);
	}
	
	@Override
	public <T> TypedQuery<T> createQuery(TypedQuery<T> query, int first, int maxResult, Class<T> clazz) {
		return query.setFirstResult(first).setMaxResults(maxResult).setHint("org.hibernate.cacheable", true);
	}
	
	@Override
	public <T> T findPrev(Object o) {
		return findPrev(o, "id");
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public <T> T findPrev(Object o, String key) {
		Object k = null;
		try {
			k = o.getClass().getMethod("getId", new Class[]{}).invoke(o, new Object[]{}); 
		} catch (Exception e) {
			e.printStackTrace();
		}
		return (T) querySingleResult(createQuery("from " + o.getClass().getName() + " where " + key + " < :key" + " order by " + key + " desc", o.getClass()).setParameter("key", k));
	}
	
	@Override
	public <T> T findNext(Object o) {
		return findNext(o, "id");
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public <T> T findNext(Object o, String key) {
		Object k = null;
		try {
			k = o.getClass().getMethod("getId", new Class[]{}).invoke(o, new Object[]{}); 
		} catch (Exception e) {
			e.printStackTrace();
		}
		return (T) querySingleResult(createQuery("from " + o.getClass().getName() + " where " + key + " > :key" + " order by " + key + " asc", o.getClass()).setParameter("key", k));
	}
	
	
	
}
